import { PostComments, Share, } from '@/app/(main)/(home)/posts/[slug]/page.client'; import { PostJsonLd } from '@/components/json-ld'; import { RichText } from '@/components/rich-text'; import { Section } from '@/components/section'; import { TagCard } from '@/components/tags/tag-card'; import { createMetadata } from '@/lib/metadata'; import { metadataImage } from '@/lib/metadata-image'; import { getPostBySlug, getAllPostSlugs, type BlogPost, } from '@/lib/payload-posts'; import { type Page as MDXPage, getPost, getPosts } from '@/lib/source'; import { cn } from '@/lib/utils'; import { File, Files, Folder } from 'fumadocs-ui/components/files'; import { InlineTOC } from 'fumadocs-ui/components/inline-toc'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import defaultMdxComponents from 'fumadocs-ui/mdx'; import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import Balancer from 'react-wrap-balancer'; import { description as homeDescription } from '@/app/(main)/layout.config'; // MDX 文章 Header function MdxHeader(props: { page: MDXPage; tags?: string[] }) { const { page, tags } = props; return (

{page.data.title}

{page.data.description}

{tags?.map((tag) => ( ))}
); } // Payload 文章 Header function PayloadHeader(props: { post: BlogPost }) { const { post } = props; return (

{post.title}

{post.description}

{post.tags?.map((tag) => ( ))}
); } // MDX 文章内容 function MdxContent({ page }: { page: MDXPage }) { const { body: Mdx, toc, tags, lastModified } = page.data; const lastUpdate = lastModified ? new Date(lastModified) : undefined; return ( <>

Written by

{page.data.author}

Created At

{new Date(page.data.date ?? page.file.name).toDateString()}

{lastUpdate && (

Updated At

{lastUpdate.toDateString()}

)}
); } // Payload 文章内容 function PayloadContent({ post }: { post: BlogPost }) { return ( <>
} className="flex-1 px-4" enableProse={true} />

Written by

{post.author}

Created At

{post.date.toDateString()}

Updated At

{post.updatedAt.toDateString()}

); } export default async function Page(props: { params: Promise<{ slug: string }>; }) { const params = await props.params; // 先尝试获取 MDX 文章 const mdxPage = getPost([params.slug]); if (mdxPage) { return ; } // 再尝试获取 Payload 文章 const payloadPost = await getPostBySlug(params.slug); if (payloadPost) { return ; } // 都找不到则 404 notFound(); } export async function generateMetadata(props: { params: Promise<{ slug: string }>; }): Promise { const params = await props.params; // 先尝试 MDX 文章 const mdxPage = getPost([params.slug]); if (mdxPage) { const title = mdxPage.data.title; const description = mdxPage.data.description ?? homeDescription; return createMetadata( metadataImage.withImage(mdxPage.slugs, { title, description, openGraph: { url: `/posts/${mdxPage.slugs.join('/')}`, }, alternates: { canonical: mdxPage.url, }, }) ); } // 再尝试 Payload 文章 const payloadPost = await getPostBySlug(params.slug); if (payloadPost) { return createMetadata({ title: payloadPost.title, description: payloadPost.description || homeDescription, openGraph: { url: `/posts/${payloadPost.slug}`, }, alternates: { canonical: `/posts/${payloadPost.slug}`, }, }); } return {}; } export async function generateStaticParams(): Promise<{ slug: string }[]> { // MDX 文章的 slugs const mdxSlugs = getPosts() .map((page) => page.slugs[0]) .filter((slug): slug is string => !!slug) .map((slug) => ({ slug })); // Payload 文章的 slugs const payloadSlugs = await getAllPostSlugs(); const payloadParams = payloadSlugs.map((slug) => ({ slug })); return [...mdxSlugs, ...payloadParams]; }